// Package contextUtils
// @File: requestContext.go
// @Description: 请求上下文工具包
// @Author: YaoRuiQi
// @Date: 2025/8/23 02:52

package contextUtils

import (
	"GinStandardTemplate/internal/pkg/jwt"
	"context"
	"errors"
	"sync"

	"github.com/nicksnyder/go-i18n/v2/i18n"
	"go.uber.org/zap"
)

type RequestContext struct {
	RequestID string                 // 请求ID
	Logger    *zap.Logger            // 日志组件
	Localizer *i18n.Localizer        // 国际化组件
	UserData  *jwt.UserClaims        // 用户数据
	Ctx       context.Context        // 上下文
	store     map[string]interface{} // 存储数据
	storeLock sync.RWMutex           // 存储数据读写锁
}

// Key 用于 context 存取，避免冲突
type ctxKey struct{}

// requestContextKey 作为 context 的 key，保证唯一
var requestContextKey = &ctxKey{}

// NewRequestContext
//
//	@Description: 向 context 注入 RequestContext
//	@param ctx 已有的 context，一般是 c.Request.Context()
//	@param logger 日志组件
//	@param localizer 国际化组件
//	@return context.Context 新的 context，携带 RequestContext
func NewRequestContext(ctx context.Context, reqContent *RequestContext) context.Context {
	return context.WithValue(ctx, requestContextKey, reqContent)
}

// FromContext
//
//	@Description: 从 context 中获取 RequestContext
//	@param ctx 上下文
func FromContext(ctx context.Context) (*RequestContext, error) {
	if rc, ok := ctx.Value(requestContextKey).(*RequestContext); ok {
		return rc, nil
	}
	return nil, errors.New("请求上下文未找到RequestContext")
}

// Set
//
//	@Description: 设置存储数据
//	@receiver rc
//	@param key 存储数据的 key
//	@param value 存储数据的 value
func (rc *RequestContext) Set(key string, value interface{}) {
	rc.storeLock.Lock()
	defer rc.storeLock.Unlock()
	if rc.store == nil {
		rc.store = make(map[string]interface{})
	}
	rc.store[key] = value
}

// Get
//
//	@Description: 获取存储数据
//	@receiver rc
//	@param key 存储数据的 key
//	@return interface{} 存储数据的 value
//	@return bool 是否找到
func (rc *RequestContext) Get(key string) (interface{}, bool) {
	rc.storeLock.RLock()
	defer rc.storeLock.RUnlock()
	if rc.store == nil {
		return nil, false
	}
	value, ok := rc.store[key]
	return value, ok
}
